import googledocs
import time

class database_local:
  """Local interface to GoogleDOCS database."""
  db_client = None
  synchronized = False
  modified = False
  db_local = None
  new_book_id = 0
  new_note_id = 0
  
  def __init__(self, username='cvutpoznamky@gmail.com', password='osklivyheslo'):
    try:
      self.db_client = googledocs.database(username, password)
      self.connected = True
    except:
      self.connected = False
    self.synchronized = False
    self.modified = False
    self.db_local = []
    self.new_book_id = 1
    self.new_note_id = 1
    self.username = username
    
  def connect(self, username, password):
    try:
      self.db_client = googledocs.database(username, password)
    except:
      return False
    self.connected = True
    self.synchronized = False
    self.modified = False
    self.db_local = []
    self.new_book_id = 1
    self.new_note_id = 1
    self.username = username
    return True
    
  def update(self):
    """Create dictionary of {'id', 'name', author', 'isbn', 'descr', 'genre', 'tags'} and assign it to self.db_local variable
    Sets synchronized flag to True, modified flag to False
    Returns: True on successful structure creation
    """
    # 
    # sets state to notes and books - allowed states are: unmodified, modified, created, deleted
    if self.connected == False:
      return False
    self.db_local = []
    books = self.db_client.listBooks()
    for i, book in enumerate(books):        # book = {}
      bookNotes = self.db_client.getNotesByBookID(book['id'])  # bookNotes = [{}]
      for note in bookNotes:  # note = {}
        note['state'] = 'unmodified'
      book['notes'] = bookNotes
      """
      bookShares = self.db_client.getBookShares(book_id=book['id'])
      for share in bookShares: # share = {}
        share['state'] = 'unmodified'
      book['shares'] = bookShares
      """
      book['state'] = 'unmodified'
      self.db_local.append(book)
    self.synchronized = True
    self.modified = False
    return True
    
  def commit(self):
    """Commit local changes to network server.
    !!--!! Modifies local structures (new ID). Re-list informations after commit !!--!! 
    Sets modified flag to False
    Returns: True on successful structure commit, False if object is not synchronized
    Note: implement Exception handling (ret False on problem)  
    """
    if(self.synchronized == False):
      return False
    if(self.modified == False): 
      return True
    for book in self.db_local[:]:
      if(book['state'] == 'deleted'):
        self.db_client.deleteBook(book['id'])
        self.db_local.remove(book)
        continue
        
      if(book['state'] == 'created'):
        book['id'] = self.db_client.createNewBook(book_name=book['name'], author=book['author'], isbn=book['isbn'], descr=book['descr'], genre=book['genre'], tags=book['tags'], cretimestamp=book['cretimestamp'],modtimestamp=book['modtimestamp'], creuser=book['creuser'], moduser=book['moduser'])
        book['state'] = 'unmodified'
        
      if(book['state'] == 'modified'):
        self.db_client.updateBook(book_id=book['id'], name=book['name'], author=book['author'], isbn=book['isbn'], descr=book['descr'], genre=book['genre'], tags=book['tags'], modtimestamp=book['modtimestamp'], moduser=book['moduser'])
        book['state'] = 'unmodified'
        
      for note in book['notes'][:]:
        if(note['state'] == 'deleted'):
          self.db_client.deleteNote(book_id=book['id'], note_id=note['id'])
          book['notes'].remove(note)
          continue  
      
        if(note['state'] == 'created'):
          note['id'] = self.db_client.createNote(book_id=book['id'], header=note['header'], body=note['body'], tags=note['tags'], cretimestamp=note['cretimestamp'], modtimestamp=note['modtimestamp'], creuser=note['creuser'], moduser=note['moduser'])
          note['state'] == 'unmodified'
          
        if(note['state'] == 'modified'):
          self.db_client.updateNote(book_id=book['id'], note_id=note['id'], header=note['header'], body=note['body'], tags=note['tags'], modtimestamp=note['modtimestamp'], moduser=note['moduser'])
          note['state'] = 'unmodified'
      """
      for acl in book['shares'][:]:
        if acl['state'] == 'created':
          self.db_client.createBookShare(book_id=book['id'], target_user=acl['user'])
          acl['state'] == 'unmodified'
        if acl['state'] == 'deleted':
          self.db_client.removeBookShare(book_id=book['id'], target_user=acl['user'])
          book['shares'].remove(acl)
      """
    return True
  
  def createNewBook(self, book_name, author='N/A', isbn='N/A', descr='N/A', genre='N/A', tags='', cretimestamp='', modtimestamp='', creuser='', moduser=''):
    """Create new book and set its name.
      Args:  book_name - book name
      [author] - default 'N/A'
      [isbn] - default 'N/A'
      [descr] - default 'N/A'
			[genre] - default 'N/A'
			[tags] - default ''
      [cretimestamp] - default '', inserts time.time()
      [modtimestamp] - default '', inserts time.time()
      [creuser] - default '', inserts username
      [moduser] - default '', inserts username
      Returns: new book unique identifier, -1 if error
    """
    if(self.synchronized == False): 
      return -1
      
    if book_name == "" or len(book_name) > 30:
        return -1

    if cretimestamp is '':
        cretimestamp = str(time.time())

    if modtimestamp is '':
        modtimestamp = str(time.time())

    if creuser is '':
        creuser = self.username

    if moduser is '':
        moduser = self.username

    self.new_book_id += 1
    new_book = {'id':self.new_book_id, 'name':book_name, 'author':author, 'isbn':isbn, 'descr':descr, 'genre':genre, 'tags':tags, 'cretimestamp':cretimestamp, 'modtimestamp':modtimestamp, 'creuser':creuser, 'moduser':moduser, 'state':'created', 'notes':[]}
    self.db_local.append(new_book)
    self.modified = True
    return self.new_book_id   
    
  def listBooks(self, book_name=None):
    """Returns a collection of available books. Result set can be filtered by name (partial match).
      Returns empty list if object is not synchronized. 
      Arg: [book_name] - name filter
      Returns: list of dictionaries {'id', 'name', author', 'isbn', 'descr', 'genre', 'tags', 'cretimestamp', 'modtimestamp', 'creuser', 'moduser'}, where ID = Google Docs spreadsheet identifier
    """
    ret = []
    if(self.synchronized == False):
      return ret
    for book in self.db_local:
      if(book['state'] != 'deleted'):
        if(book_name is not None):
          if(book_name in book['name']):
            ret_book = {'id':book['id'], 'name':book['name'], 'author':book['author'], 'isbn':book['isbn'], 'descr':book['descr'], 'genre':book['genre'], 'tags':book['tags'], 'cretimestamp':book['cretimestamp'], 'modtimestamp':book['modtimestamp'], 'creuser':book['creuser'], 'moduser':book['moduser']}
            ret.append(ret_book)
        else:
          ret_book = {'id':book['id'], 'name':book['name'], 'author':book['author'], 'isbn':book['isbn'], 'descr':book['descr'], 'genre':book['genre'], 'tags':book['tags'], 'cretimestamp':book['cretimestamp'], 'modtimestamp':book['modtimestamp'], 'creuser':book['creuser'], 'moduser':book['moduser']}
          ret.append(ret_book)
    return ret      

  def deleteBook(self, book_id):
    """Sets deleted flag to book in local structure.
      Returns empty list if object is not synchronized.
      Arg: book_id - Google Docs spreadsheet identifier
      Returns: boolean success
    """
    if(self.synchronized == False):
      return False
    for book in self.db_local:     
      if(book['id'] == book_id) and (book['state'] != 'deleted'):
        if(book['state'] == 'created'):
          self.db_local.remove(book)
          return True
        notes = self.getNotesByBookID(book["id"])
        for note in notes:
            self.deleteNote(book["id"], note["id"])
        book['state'] = 'deleted'
        self.modified = True
        return True
    return False    
    
  def updateBook(self, book_id, name=None, author=None, isbn=None, descr=None, genre=None, tags=None, modtimestamp=None, moduser=None):
    """Updates book info.
      Returns False if object is not synchronized.
  	  Args: book_id - Google Docs spreadsheet identifier
  			[name] - new book name
        [author]
  			[isbn]
  			[descr]
  			[genre]
  			[tags]  
        [modtimestamp]
        [moduser]
  	  Returns: boolean success	
    """
    if(self.synchronized == False):
      return False 
    if name=="" or len(name) > 30:
      return False
    for book in self.db_local:
      if(book['id'] == book_id) and (book['state'] != 'deleted'):
        modified = False
        if(name is not None):
          book['name'] = name
          modified=True
        if(author is not None):
          book['author'] = author
          modified=True
        if(isbn is not None):
          book['isbn'] = isbn
          modified=True
        if(descr is not None):
          book['descr'] = descr
          modified=True
        if(genre is not None):
          book['genre'] = genre
          modified=True
        if(tags is not None):
          book['tags'] = tags
          modified=True
        
        if modified or moduser is not None or modtimestamp is not None:
          if moduser is not None:
            book['moduser'] = moduser
          else:
            book['moduser'] = self.username
            
          if modtimestamp is not None:
            book['modtimestamp'] = str(modtimestamp)
          else:
            book['modtimestamp'] = str(time.time())
          modified = True  
          
        if(modified and book['state'] != 'created'):
          book['state'] = 'modified' 
          self.modified = True
        return True
    return False

  def createNote(self, book_id, header="N/A", body="N/A", tags="", cretimestamp=None, modtimestamp=None, creuser=None, moduser=None):
    """Creates note for selected book.
      Args: book_id - Google Docs spreadsheet identifier
            [header] - note header
            [body] - body input
            [tags] - tags divided by comma
            [cretimestamp] - creation timestamp (date.date())
            [modtimestamp] - modification timestamp (date.date())
            [creuser] - creator
            [moduser] - modificator
      Return: created note id or -1 in case of an error
    """
    if(self.synchronized == False):
      return -1
    for book in self.db_local:
      if(book['id'] == book_id):      
        self.new_note_id += 1
        new_note = {'id':self.new_note_id, 'header':header, 'body':body, 'tags':tags, 'state':'created'}
        
        if cretimestamp is not None:
          new_note['cretimestamp'] = str(cretimestamp)
        else:
          new_note['cretimestamp'] = str(time.time())
          
        if modtimestamp is not None:
          new_note['modtimestamp'] = str(modtimestamp)
        else:
          new_note['modtimestamp'] = str(time.time())
          
        if creuser is not None:
          new_note['creuser'] = creuser
        else:
          new_note['creuser'] = self.username
          
        if moduser is not None:
          new_note['moduser'] = moduser
        else:
          new_note['moduser'] = self.username
          
        book['notes'].append(new_note) 
        self.modified = True
        
        return self.new_note_id
    return -1
    
  def getNotesByBookID(self, book_id):
    """Returns a collection of notes stored for selected book.
      Returns empty list if object is not synchronized.
      Arg: book_id - Google Docs spreadsheet identifier
      Returns: list of dictionaries - dictionary contains keys: id, header, body, tags, cretimestamp, modtimestamp, creuser, moduser
    """
    if(self.synchronized == False):
      return []
    for book in self.db_local:
      if(book['id'] == book_id) and (book['state'] != 'deleted'):
        ret = []
        for note in book['notes']:
          ret_note = {'id':note['id'], 'header':note['header'], 'body':note['body'], 'tags':note['tags'], 'cretimestamp':note['cretimestamp'], 'modtimestamp':note['modtimestamp'], 'creuser':note['creuser'], 'moduser':note['moduser']}
          ret.append(ret_note)
        return ret
    return []
    
        
  def getNewestNotes(self, book_id=None):
    """Returns collection of notes ordered by modification date in descending order
    Arg: book_id - if None then all books are selected
    Returns: list of dictionaries - dictionary contains keys: book_id, note_id, header, body, tags, cretimestamp, modtimestamp, creuser, moduser 
    """
    ret = []
    for book in self.db_local:
      if book['state'] != 'deleted':
          for note in book['notes']:
            if note['state'] != 'deleted':
                note['book_id'] = book['id']
                ret.append(note)
    sorted(ret, key=lambda id: id['id'])
    return ret
    
  def updateNote(self, book_id, note_id, header=None, body=None, tags=None, modtimestamp=None, moduser=None):
    """Update book note defined by id.
      Returns False if object is not synchronized.
      Args: book_id - Google Docs spreadsheet identifier, represents book containing the note
            note_id - note identificator
            [header] - note data
            [body] - note data
            [tags] - note data  
            [modtimestamp] - modification timestamp
            [moduser] - modificator
      Returns: boolean success    
    """
    if(self.synchronized == False):
      return False
    for book in self.db_local:
      if(book['id'] == book_id) and (book['state'] != 'deleted'):
        for note in book['notes']:
          if(note['id']==note_id) and (note['state'] != 'deleted'):
            modified = False
            if(header is not None):
              note['header'] = header
              modified = True
            if(body is not None):
              note['body'] = body   
              modified = True
            if(tags is not None):
              note['tags'] = tags  
              modified = True
            if modified or modtimestamp is not None or moduser is not None:                        
              
              if modtimestamp is not None:
                note['modtimestamp'] = str(modtimestamp)
              else:
                note['modtimestamp'] = str(time.time())
                
              if moduser is not None:
                note['moduser'] = moduser
              else:
                note['moduser'] = self.username
                
              if(note['state'] != 'created'):
                note['state'] = 'modified' 
              self.modified = True
              return True
            return False
    return False
    
  def deleteNote(self, book_id, note_id):
    """Delete note by id
      Returns False if object is not synchronized.
      Args: book_id - Google Docs spreadsheet identifier
            note_id - note to be deleted
      Returns: boolean success    
    """ 
    if(self.synchronized == False):
      return False
    for book in self.db_local:
      if(book['id'] == book_id) and (book['state'] != 'deleted'):
        for note in book['notes']:
          if(note['id']==note_id) and (note['state'] != 'deleted'):
            note['state'] = 'deleted'
            self.modified = True
            return True
    return False
    
#   def createBookShare(self, book_id, target_user):
#     """Creates or modifies share to user defined by target_user with writing permissions.
#       Args: book_id - Google Docs spreadsheet identifier
#             target_user - email of target GoogleDOCS account
#       Returns : boolean success      
#     """
#     for book in self.db_local:
#       if(book['id'] == book_id) and (book['state'] != 'deleted'):
#         for acl in book['shares']:
#           if acl['user'] == target_user:
#             return False
#         new_acl = {'user':target_user, 'role':'writer', 'state':'created'}
#         book['shares'].append(new_acl)
#         self.modified = True
#         return True
#     return False
# 
#   def removeBookShare(self, book_id, target_user):
#     """Removes share to user defined by target_user. Cannot remove owner.
#       Args: book_id - Google Docs spreadsheet identifier
#             target_user - email of target GoogleDOCS account
#       Returns : boolean success      
#     """         
#     for book in self.db_local:
#       if(book['id'] == book_id) and (book['state'] != 'deleted'):
#         for acl in book['shares'][:]:
#           if acl['user'] == target_user:
#             if acl['state'] == 'created':
#               book['shares'].remove(acl)
#               return True
#             else:              
#               acl['state'] = 'deleted'
#               self.modified = True
#               return True
#     return False
#  
#   def getBookShares(self, book_id, user=None):
#     """Reads shares on spreadsheet and returns them in list of tuples
#       Args: book_id - Google Docs spreadsheet identifier
#             [user] - email of target GoogleDOCS account
#       Returns : [{user, role}] - list of dictionaries
#     """                                                          
#     ret = []
#     for book in self.db_local:
#       if(book['id'] == book_id) and (book['state'] != 'deleted'):
#         if user is None:
#           for acl in book['shares']:
#             ret.append({'user':acl['user'], 'role':acl['role']})
#             self.modified = True
#         else:
#           for acl in book['shares']:
#             if(user == acl['user']):
#               ret.append({'user':acl['user'], 'role':acl['role']})
#               self.modified = True
#     return ret    


      
if __name__ == '__main__':
  x = database_local()               
  print x.update()           
  a = '0AqSWlRWYPabFdG9uRHlKdDY5MGxENG9CRWV1aHk2eUE'       
  print x.getBookShares(book_id=a)
  print x.createBookShare(book_id=a, target_user='jirka.kulovany@seznam.cz')
  print x.getBookShares(book_id=a)
  print x.commit()
  print x.update()
  print x.getBookShares(book_id=a)
  print x.removeBookShare(book_id=a, target_user='jirka.kulovany@seznam.cz')
  print x.commit()
    